package com.itheima.tliasmanager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.itheima.bcript.BCryptUtil;
import com.itheima.tliasmanager.annotation.Log;
import com.itheima.tliasmanager.exception.PasswordNotMatchException;
import com.itheima.tliasmanager.exception.UsernameNotExistException;
import com.itheima.tliasmanager.mapper.DeptMapper;
import com.itheima.tliasmanager.mapper.EmpExprMapper;
import com.itheima.tliasmanager.mapper.EmpMapper;
import com.itheima.tliasmanager.pojo.domain.Dept;
import com.itheima.tliasmanager.pojo.domain.Emp;
import com.itheima.tliasmanager.pojo.domain.EmpExpr;
import com.itheima.tliasmanager.pojo.domain.EmpLog;
import com.itheima.tliasmanager.pojo.dto.QueryParam;
import com.itheima.tliasmanager.pojo.vo.PageResult;
import com.itheima.tliasmanager.service.EmpLogService;
import com.itheima.tliasmanager.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.FileNotFoundException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Service
public class EmpServiceImpl  extends ServiceImpl<EmpMapper, Emp> implements EmpService {


    @Autowired
    private EmpExprMapper empExprMapper;


    @Autowired
    private EmpLogService empLogService;


    @Autowired
    private BCryptUtil bCryptUtil;
    @Autowired
    private DeptMapper deptMapper;


    /**
     * 分页+多条件查询
     * @param queryParam
     * @return
     */
    @Override
    public PageResult<Emp> page(QueryParam queryParam) {
        //1.创建封装分页信息的Page对象
        //功能1：封装分页查询的请求参数（页码，条数）
        //功能2：封装分页查询结果（总条数，数据）
        Page<Emp> page = Page.of(queryParam.getPage(), queryParam.getPageSize());



        //构建条件构建器
        LambdaQueryWrapper<Emp> wrapper = new LambdaQueryWrapper<Emp>()
                .like(queryParam.getName()!= null   ,   Emp::getName    ,    queryParam.getName())  //name  like  %?%
                .eq(queryParam.getGender()!=null    ,   Emp::getGender  , queryParam.getGender())  //gender = ?
                .between( queryParam.getBegin()!=null  &&  queryParam.getEnd() !=null  , Emp::getEntryDate, queryParam.getBegin(), queryParam.getEnd())//entry_date between ? and ?
                .orderByDesc(Emp::getUpdateTime); // order by update_time desc

        //2.调用mybatisplus提供的分页功能方法
        page = page(page  , wrapper); //调用mybatisplus提供的业务层 分页功能 方法
        //page = empMapper.selectPage(page, null);  //调用mybatisplus提供的持久层分页 方法

        //3.自行查询并封装部门名称
        List<Emp> empList = page.getRecords();
        //3.1 如果员工列表不为空，处理部门名称
        if(empList != null && empList.size() > 0){

            //3.1 获取所有员工所属的部门id
            List<Integer> deptIdList = empList.stream().map(emp -> emp.getDeptId()).collect(Collectors.toList());

            //3.2 判断部门id列表不为空
            if(deptIdList != null && deptIdList.size() > 0){

                //3.3 调用mapper方法，查询部门信息
                List<Dept> deptList = deptMapper.selectBatchIds(deptIdList);

                //3.4 判断部门列表不为空
                if( deptList != null && deptList.size() > 0){

                    //3.5 遍历所有员工
                    empList.stream().forEach(emp -> {
                        //3.6 获取每一个员工，在部门列表中查找部门信息
                        List<Dept> result = deptList.stream().filter(dept -> dept.getId() == emp.getDeptId()).collect(Collectors.toList());;
                        if(result != null && result.size() > 0){
                            emp.setDeptName(result.get(0).getName());
                        }
                    });
                }
            }
        }
        //4.封装分页结果数据
        return new PageResult<>(page.getTotal(),page.getRecords());
    }


    /**
     *
     * 保存员工信息
     * @param emp
     */
    @Transactional( rollbackFor = Exception.class)  //默认只能处理运行时的事务管理
    @Override
    public void saveEmp(Emp emp) throws FileNotFoundException {

        try {
            //1.添加员工信息
            //1.1 设置员工的基础信息（createTime/updateTime）
            emp.setCreateTime(LocalDateTime.now());
            emp.setUpdateTime(LocalDateTime.now());
            //对密码进行加密
            emp.setPassword(bCryptUtil.hashPassword("123456"));

            //1.2 调用员工的Mapper，保存员工信息
            save( emp );
            log.info("保存员工信息：{}", emp);

            //2.添加员工工作经历信息
            List<EmpExpr> exprList = emp.getExprList();

            //实现方案一：循环多次添加（效率低）
            //实现方案二：批量添加（效率高）
            //2.1 调用员工工作经历持久层Mapper，批量添加员工工作经历信息
            if (exprList != null && !exprList.isEmpty()) {

                //2.2 遍历当前所有员工工作经历，设置员工id
                exprList.forEach(ex -> ex.setEmpId(emp.getId()));

                empExprMapper.insert(exprList);
            }
        } finally { // 确保记录日志的操作，无论正常还是异常都会执行，无法避免数据库回滚
            //3.记录日志
            //3.1 创建日志对象，封装日志数据
            EmpLog empLog = new EmpLog(null, LocalDateTime.now(), "添加员工：" + emp.getName());

            //3.2 调用日志业务方法，记录日志
            empLogService.insertLog(empLog);
        }


    }




    /**
     * 批量删除员工
     * @param ids
     */
    @Transactional( rollbackFor = Exception.class )
    @Override
    public void batchRemove(List<Integer> ids) {
        //1.批量删除员工数据：delete  from  emp  where  id in(1,2,3,4,5,6,7);
        //empMapper.deleteByIds(ids); 正确
        //removeBatchByIds(ids); 有误
        remove(new QueryWrapper<Emp>().in("id",ids)); //正确

        //2.批量删除员工工作经历：delete  from  emp_expr where  emp_id in(1,2,3,4,5,6,7);

        //2.1查询多个员工是否有工作经历
                                                //  select * from emp_expr where emp_id in(1,2,3,4,5,6,7);
        List<EmpExpr> empExprs = empExprMapper.selectList(new LambdaQueryWrapper<EmpExpr>().in(EmpExpr::getEmpId, ids));

        //2.2批量删除员工工作经历
        if(empExprs != null && empExprs.size() > 0){
                                                // delete from  emp_expr where  emp_id in(1,2,3,4,5,6,7);
            empExprMapper.delete(new LambdaQueryWrapper<EmpExpr>().in(EmpExpr::getEmpId, ids));
        }

    }


    /**
     * 查询员工详情
     * @param id
     * @return
     */
    @Log
    @Override
    public Emp queryDetail(Integer id) {
        //1.调用mapper查询员工详情
        //select  * from emp  where  id = ?
        Emp emp = getById(id);

        //select  *  from emp_expr  where emp_id
        List<EmpExpr> empExprs = empExprMapper.selectList(new LambdaQueryWrapper<EmpExpr>().eq(EmpExpr::getEmpId, id));

        //合并数据
        emp.setExprList(empExprs);

        return emp;
    }


    /**
     * 修改员工
     * @param emp
     */
    @Transactional( rollbackFor = Exception.class )
    @Override
    public void updateEmp(Emp emp) {
        //提前考虑清楚：涉及到两张表，emp/emp_expr
        //1.更新员工表
        update(emp, new QueryWrapper<Emp>().eq("id",emp.getId()));  //底层：默认动态SQL

        //2.更新员工对应的工作经历表
        //2.1 先删除                 //delete from  emp_expr  where  emp_id = ?;
        empExprMapper.delete(new LambdaQueryWrapper<EmpExpr>().eq(EmpExpr::getEmpId,emp.getId()));

        //2.2 再添加
        //设置新增的工作经历归属的员工id                设置工作经历的员工id
        if(emp.getExprList()!=null && !emp.getExprList().isEmpty()){
            emp.getExprList().stream().forEach(expr->expr.setEmpId(emp.getId()));
            empExprMapper.insert(emp.getExprList());
        }

    }

    /**
     * 登录功能
     * @param emp
     * @return
     */
    @Override
    public Emp checkLogin(Emp emp) {
        //1.调用mapper方法，查询用户名是否存在（select * from emp  where username = #{username}）
        Emp loginEmp = this.getOne(new LambdaQueryWrapper<Emp>().eq(Emp::getUsername, emp.getUsername()));

        //2.判断用户名是否存在，如果不存在，登录失败。
        if(loginEmp == null){
            throw new UsernameNotExistException("用户名不存在！");
        }

        //3.如果用户名存在，继续校验密码是否正确。如果不正确，登录失败。
        if(!bCryptUtil.checkPassword(emp.getPassword(), loginEmp.getPassword())){
            throw new PasswordNotMatchException("密码错误！");
        }

        //4.登录成功，返回用户信息
        return loginEmp;
    }


}





